package spring.security.core.support;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;

import com.fasterxml.jackson.core.Base64Variants;
import com.fasterxml.jackson.core.JsonGenerator.Feature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.BaseSettings;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.StdDateFormat;
import com.google.common.base.Strings;

import spring.security.core.util.DateUtils;

public class JsonObjectMapper extends ObjectMapper {
	
	private static final long serialVersionUID = 1L;
	private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getDefault();

	public JsonObjectMapper() {
		this((String) null, (String) null);
	}

	public JsonObjectMapper(String dateFormat, String timeZone) {
		if (Strings.isNullOrEmpty(dateFormat)) {
			this.setDateFormat(DateUtils.LONG_DATE_FORMAT);
		} else {
			this.setDateFormat(new SimpleDateFormat(dateFormat));
		}

		TimeZone zone = null;
		if (Strings.isNullOrEmpty(timeZone)) {
			zone = DEFAULT_TIME_ZONE;
			this.setTimeZone(DEFAULT_TIME_ZONE);
		} else {
			this.setTimeZone(zone = TimeZone.getTimeZone(timeZone));
		}

		try {
			Field e = ObjectMapper.class.getDeclaredField("DEFAULT_BASE");
			BaseSettings bs = new BaseSettings(null, DEFAULT_ANNOTATION_INTROSPECTOR,
					null, null, TypeFactory.defaultInstance(), null,
					StdDateFormat.instance, null, Locale.getDefault(), zone,
					Base64Variants.getDefaultVariant());
			setFinalStatic(e, bs);
		} catch (Exception arg5) {
			arg5.printStackTrace();
		}

		this.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true);
		this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		this.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
		this.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
	}

	private static void setFinalStatic(Field field, Object newValue) throws Exception {
		field.setAccessible(true);
		Field modifiersField = Field.class.getDeclaredField("modifiers");
		modifiersField.setAccessible(true);
		modifiersField.setInt(field, field.getModifiers() & -17);
		field.set((Object) null, newValue);
	}
	
}
